#include "DINPUT8.hpp"

namespace Mydll{
	HINSTANCE hHjDLLTarget; 

	HRESULT WINAPI DirectInput8Create ( 
      HINSTANCE hinst,
      DWORD dwVersion,
      REFIID riidltf,
      LPVOID *ppvOut,
      LPUNKNOWN punkOuter 
      )
  {  
	  static decltype(&DirectInput8Create) mFuncAddr=NULL;
	  if(NULL == mFuncAddr){				
		  std::stringstream ss;
		  ss<<(char*)(strchr(__FUNCTION__,':')+2);
		  std::string strFullFuncName=ss.str();
		  TCHAR *LPCTSTRFuncname=new TCHAR[strFullFuncName.size()+sizeof(TCHAR)*1];
		  LPCTSTRFuncname[strFullFuncName.size()]=(TCHAR)'\0';
		  std::copy(strFullFuncName.begin(),strFullFuncName.end(),LPCTSTRFuncname);

		  mFuncAddr=(decltype(&DirectInput8Create))GetProcAddress(Mydll::hHjDLLTarget, LPCTSTRFuncname);
	  }
    HRESULT hr=(HRESULT)mFuncAddr(hinst,dwVersion,riidltf,ppvOut,punkOuter);
	//MessageBoxA(0,__FUNCTION__,__FUNCTION__,MB_OK);
    
    if(SUCCEEDED(hr)){
  		*ppvOut = new MyDirectInput8(reinterpret_cast<IDirectInput8*>(*ppvOut));
  	}
      return hr;
  }
}



HRESULT __stdcall Mydll::DllCanUnloadNow(void){
	static decltype(&Mydll::DllCanUnloadNow) mFuncAddr=NULL;
	if(NULL == mFuncAddr){				
		std::stringstream ss;
		ss<<(char*)(strchr(__FUNCTION__,':')+2);
		std::string strFullFuncName=ss.str();
		TCHAR *LPCTSTRFuncname=new TCHAR[strFullFuncName.size()+sizeof(TCHAR)*1];
		LPCTSTRFuncname[strFullFuncName.size()]=(TCHAR)'\0';
		std::copy(strFullFuncName.begin(),strFullFuncName.end(),LPCTSTRFuncname);

		mFuncAddr=(decltype(&Mydll::DllCanUnloadNow))GetProcAddress(Mydll::hHjDLLTarget, LPCTSTRFuncname);
	}
	HRESULT hr=mFuncAddr();
	return hr;
}

HRESULT __stdcall Mydll::DllGetClassObject(
  _In_   REFCLSID rclsid,
  _In_   REFIID riid,
  _Out_  LPVOID *ppv
){
	static decltype(&Mydll::DllGetClassObject) mFuncAddr=NULL;
	if(NULL == mFuncAddr){				
		std::stringstream ss;
		ss<<(char*)(strchr(__FUNCTION__,':')+2);
		std::string strFullFuncName=ss.str();
		TCHAR *LPCTSTRFuncname=new TCHAR[strFullFuncName.size()+sizeof(TCHAR)*1];
		LPCTSTRFuncname[strFullFuncName.size()]=(TCHAR)'\0';
		std::copy(strFullFuncName.begin(),strFullFuncName.end(),LPCTSTRFuncname);

		mFuncAddr=(decltype(&Mydll::DllGetClassObject))GetProcAddress(Mydll::hHjDLLTarget, LPCTSTRFuncname);
	}
	HRESULT hr=mFuncAddr(rclsid,riid,ppv);
	return hr;
}

HRESULT __stdcall Mydll::DllRegisterServer(void){
	static decltype(&Mydll::DllRegisterServer) mFuncAddr=NULL;
	if(NULL == mFuncAddr){				
		std::stringstream ss;
		ss<<(char*)(strchr(__FUNCTION__,':')+2);
		std::string strFullFuncName=ss.str();
		TCHAR *LPCTSTRFuncname=new TCHAR[strFullFuncName.size()+sizeof(TCHAR)*1];
		LPCTSTRFuncname[strFullFuncName.size()]=(TCHAR)'\0';
		std::copy(strFullFuncName.begin(),strFullFuncName.end(),LPCTSTRFuncname);

		mFuncAddr=(decltype(&Mydll::DllRegisterServer))GetProcAddress(Mydll::hHjDLLTarget, LPCTSTRFuncname);
	}
	HRESULT hr=mFuncAddr();
	return hr;
}

HRESULT __stdcall Mydll::DllUnregisterServer(void){
	static decltype(&Mydll::DllUnregisterServer) mFuncAddr=NULL;
	if(NULL == mFuncAddr){				
		std::stringstream ss;
		ss<<(char*)(strchr(__FUNCTION__,':')+2);
		std::string strFullFuncName=ss.str();
		TCHAR *LPCTSTRFuncname=new TCHAR[strFullFuncName.size()+sizeof(TCHAR)*1];
		LPCTSTRFuncname[strFullFuncName.size()]=(TCHAR)'\0';
		std::copy(strFullFuncName.begin(),strFullFuncName.end(),LPCTSTRFuncname);

		mFuncAddr=(decltype(&Mydll::DllUnregisterServer))GetProcAddress(Mydll::hHjDLLTarget, LPCTSTRFuncname);
	}
	HRESULT hr=mFuncAddr();
	return hr;
}

BOOL APIENTRY DllMain( HMODULE hModule,
                       DWORD  ul_reason_for_call,
                       LPVOID lpReserved
           )
{
  switch (ul_reason_for_call){
	  case DLL_PROCESS_ATTACH:
	  case DLL_THREAD_ATTACH:
		  if(NULL == Mydll::hHjDLLTarget ){
			  Mydll::hHjDLLTarget = LoadLibrary(TEXT("dxdiag.dll"));			  
			  if (!Mydll::hHjDLLTarget){
				  MessageBox(0,TEXT("could not load the dynamic library"),TEXT("OAO"),0);   
				  return EXIT_FAILURE;
			  }			  
		  }
		break;
    case DLL_THREAD_DETACH:
    case DLL_PROCESS_DETACH:
    break;  
  }
  return TRUE;
}

